poj1860_最短路bellman Ford算法应用

题意简述

某城市有M(1<=M<=100)个货币兑换站,可以兑换N(1<=N<=100)种货币,每个兑换站只能互换两种货币,

且汇率与手续费各不相同。某人初始时手中有V元货币S,问他是否有可能通过货币兑换,在最后换回货币S时实现盈利,有可能则输出YES,否则输出NO。


算法分析

本题可抽象为一张有N个节点的有向图,一个兑换站就是它所兑换的两种货币间的两条有向边。边的权值有两个:汇率及手续费。

问题可化简为:从定点出发找正权环。由于可以通过无限次走正权环使得收益趋于无穷,所以不考虑返程开销。

容易发现,这是Bellman-Ford算法的逆用。将求最短路改为求最长路,再找可以无限松弛的正环,即可得解。

只要将Bellman-Ford稍微改进。初始时所有节点不再赋为无穷大,而是改为无穷小(0)。比较时,注意权值计算式的变化即可。详见程序样例。

具体的Bellman-Ford及最短路各算法另开文。

Problem Status: AC。时间32ms,内存184k


#include<stdio.h>
struct edge
{
    int a;///货币a
    int b;///货币b
    double r;///a->b的汇率
    double c;///b->a的汇率
};
int bellman_ford(double d[],struct edge x[],int n,int m,int s,double v)
{
    int i,j,flag;
    d[s]=v;
    for(i=1; i<=n-1; i++)
    {
        flag=0;
        for(j=0; j<2*m; j++)
        {
            if(d[x[j].b]<(d[x[j].a]-x[j].c)*x[j].r)
            {
                d[x[j].b]=(d[x[j].a]-x[j].c)*x[j].r;
                flag=1;
            }
        }
        if(!flag) break;
    }
    for(j=0; j<2*m; j++)
    {
        if(d[x[j].b]<(d[x[j].a]-x[j].c)*x[j].r) return 1;
    }
    return 0;
}
int main()
{
    int n,m,s,i,t=0;
    struct edge x[202];
    double v,d[101]= {0};
    ///n种货币类型,m个交换点,NICK拥有v个s种的货币
    scanf("%d%d%d%lf",&n,&m,&s,&v);
    for(i=0; i<m; i++)
    {
        ///货币a,b,a->b的汇率,a->b的手续费
        scanf("%d%d%lf%lf", &x[t].a, &x[t].b, &x[t].r, &x[t].c);
        t++;
        x[t].a=x[t-1].b;
        x[t].b=x[t-1].a;
        ///b->a的汇率,b->a的手续费
        scanf("%lf%lf", &x[t].r, &x[t].c);
        t++;
    }
    if(bellman_ford(d, x, n, m, s, v)) printf("YES\n");
    else printf("NO\n");
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值